/* ui.c */

#include <curses.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
#include "ui.h"
#include "structs.h"
#include "vie.h"
#include "window.h"
#include "highlight.h"

static int init_colors( void );
static int highlight_screen(void);

int show_error = 0;
int show_ex_string = 0;
int show_string = 0;

char error_buffer[256];
char ex_string_buffer[256];
char string_buffer[256];

int init_screen(){
	initscr();
	keypad(stdscr, TRUE);
	cbreak();
	noecho();
	init_colors();
	set_left_margin(0);
	refresh();
	return OK;
}

int end_screen(){
	endwin();
	return OK;
}


int update_screen(){	
	int j=0;
	int offset = 0;
	int print_blank = 0;
	int actual_offset = 0;
	int curr_line = 0;
	int line_count = 0;
	buf_t * cur_buf = viescr.start_buf;
	
	// if the VIE_ATTRIBUTE_NUMBER is on, count the line;OB
	if(VIE_ATTRIBUTE_NUMBER){
		buf_t * temp_buf_ptr = current_window->buf;
		buf_t * itr = NULL;
		buf_to_head();
		itr = current_window->buf;
		current_window->buf = temp_buf_ptr;
		for(;itr != NULL; itr = buf_next(itr)){
			line_count ++;
			if(itr == viescr.start_buf)
				break;
		}
	}	
	//calculate the offsets
	offset = tabmap_get_logical_offset(cur_buf->tabmap, viescr.start_line * VIE_COLS );
	if( (actual_offset = tabmap_get_actual_offset(cur_buf->tabmap, offset))/VIE_COLS < viescr.start_line){
		actual_offset = tabmap_get_actual_offset(cur_buf->tabmap, ++offset);
		j = actual_offset % VIE_COLS;
	}
	erase();
	if(VIE_ATTRIBUTE_NUMBER){
		attron(COLOR_PAIR(COLOR_PAIR_LINE_NO));
		mvprintw(0,0,"%d",line_count++);
		attroff(COLOR_PAIR(COLOR_PAIR_LINE_NO));
	}
	move(curr_line,j+VIE_LEFT_MARGIN);
	while( curr_line < LINES -1){
		
		if( print_blank ){
			attron(COLOR_PAIR(COLOR_PAIR_BLUE_ON_DEFAULT));
			attron(A_BOLD);
			mvprintw(curr_line ++, 0, "~");
			attroff(A_BOLD);
			attroff(COLOR_PAIR(COLOR_PAIR_BLUE_ON_DEFAULT));
		}else{
			char c;
			if(offset == cur_buf->len){ //goto next buf;
				curr_line ++;

				move(curr_line,VIE_LEFT_MARGIN);
				offset=0;
				actual_offset = 0;
				j = 0;
				cur_buf = buf_next(cur_buf);
				if(cur_buf == NULL){
					print_blank = 1;
				}else{

					if(VIE_ATTRIBUTE_NUMBER){
						attron(COLOR_PAIR(COLOR_PAIR_LINE_NO));
						mvprintw(curr_line,0,"%d",line_count++);
						attroff(COLOR_PAIR(COLOR_PAIR_LINE_NO));
					}
					move(curr_line,VIE_LEFT_MARGIN);
				}
				continue;
			}
			c = cur_buf->data[offset++];
			if(c == '\t'){
				int _actual_offset = (actual_offset / TAB_WIDTH +1)*TAB_WIDTH;
				int k;
				for(k = actual_offset; k < _actual_offset; k++){
					addch(' ');
					j++;
					if(j == VIE_COLS){
						j = 0;
						curr_line ++;
						move(curr_line,VIE_LEFT_MARGIN);
						if(curr_line == LINES -1)break;
					}
				}
				actual_offset = _actual_offset;
			}else{
				addch(c);
				actual_offset ++;
				j ++;
				if(j == VIE_COLS){
					j = 0;
					curr_line ++;
					move(curr_line,VIE_LEFT_MARGIN);
				}
			}
			
		}
	}
	//check highlight attribute
	if(VIE_ATTRIBUTE_HIGHLIGHT){
		highlight_screen();
	}
	//refresh the state line
	if(viescr.edit_mode == MODE_INSERT){
		attron(A_BOLD);
		move(LINES -1,0);
		clrtoeol();
		mvprintw(LINES - 1, 0, "-- INSERT --");
		attroff(A_BOLD);
	}
	if(viescr.edit_mode == MODE_EX){
		mvprintw(LINES-1, 0, ":");
	}
	if(show_error){
		move(LINES -1,0);
		clrtoeol();
		attron(COLOR_PAIR(COLOR_PAIR_ERROR) | A_BOLD);
		mvprintw(LINES -1, 0, "%s",error_buffer);
		attroff(COLOR_PAIR(COLOR_PAIR_ERROR) | A_BOLD);
		show_error = 0;
	}else if (show_ex_string){
		
		move(LINES -1,0);
		clrtoeol();
		mvprintw(LINES -1, 0, ":%s",ex_string_buffer);
		show_ex_string = 0;
	}else if(show_string){

		move(LINES -1,0);
		clrtoeol();
		mvprintw(LINES -1, 0, "%s",string_buffer);
		show_string = 0;
	}
	if(viescr.edit_mode != MODE_EX)	
		move(viescr.cursor_pos.line, viescr.cursor_pos.col+VIE_LEFT_MARGIN);
	refresh();
	return OK;
}


int update_state_area_with_string(char * str){
	
	strncpy(string_buffer, str, 256);
	show_string = 1;
	return OK;
}

int update_state_area_with_format_string_int(char * str, int arg){
	
	sprintf(string_buffer, str, arg);
	show_string = 1;
	return OK;
}

int update_state_area_with_format_string_str(char * str, char *arg){
	
	sprintf(string_buffer, str, arg);
	show_string = 1;
	return OK;
}

int update_state_area_ex(char *str, int cursor_pos){
	strncpy(ex_string_buffer, str, 256);
	show_ex_string = 1;

	return OK;
}

int state_area_show_error(const char *prompt){
	strncpy(error_buffer, prompt, 256);
	show_error = 1;
	return OK;
}

int state_area_show_format_error_str(const char *prompt, char *arg){
	sprintf(error_buffer, prompt, arg);
	show_error = 1;
	return OK;
}
int state_area_show_format__error_int(const char *prompt, int arg){
	sprintf(error_buffer, prompt, arg);
	show_error = 1;
	return OK;
}
int state_area_get_string(const char * prompt, char * buffer){
	int len;
	int MAX_STRING = 256;
	mvprintw(LINES - 1, 0,"%s", prompt);
	refresh();
	echo();
	nocbreak();
	wgetnstr(stdscr, buffer, MAX_STRING);
	len = strlen(buffer);
	if(len >0 && buffer[len - 1] == '\n')
		buffer[len -1] = '\0';
		
	noecho();
	cbreak();
	return OK;
}

static int init_colors(){

	if(has_colors()){

		if(start_color() == OK){
			//assume_default_colors(COLOR_BLACK, COLOR_WHITE | A_BOLD);
			use_default_colors();

			// init color pairs
			init_pair(COLOR_PAIR_ERROR, COLOR_WHITE, COLOR_RED);	
			init_pair(COLOR_PAIR_BLUE_ON_DEFAULT, COLOR_BLUE, -1);	
			init_pair(COLOR_PAIR_GREEN_ON_DEFAULT, COLOR_GREEN,-1);	
			init_pair(COLOR_PAIR_RED_ON_DEFAULT, COLOR_RED, -1);	
			init_pair(COLOR_PAIR_BROWN_ON_DEFAULT, COLOR_YELLOW, -1);	
			return OK;
		}
	}
	return -1;
}


int set_left_margin(int val){
	if(val>=0 && val < COLS){
		VIE_LEFT_MARGIN = val;
		VIE_COLS = COLS - val;
	}
	return OK;
}

int window_changed(){
	int left_margin = VIE_LEFT_MARGIN;
	endwin();
	init_screen();
	set_left_margin(left_margin);
	current_window->buf->last_modified_pos = viescr.cursor_pos.offset;
	roll_screen();
	return OK;
}


int highlight_screen(){

	int cur_line = 0;
	buf_t *cur_buf = NULL;
	//regx
	static regex_t preg;
	static regmatch_t match;
	
	cur_line = - viescr.start_line;
	cur_buf = viescr.start_buf;
	
	while( 1 ){
		int i;
		for(i =0; i< MAX_HIGHLIGHTS; i++){
			if(regcomp(&preg, highlight_type[i], 0)==OK){
				int offset = 0;
				while (regexec(&preg, cur_buf->data + offset, 1, &match, 0) != REG_NOMATCH) {
					//match succeed
					int start_offset = match.rm_so + offset;
					int end_offset = match.rm_eo + offset;
					int len = end_offset - start_offset;
					//do highlight work
					int actual_so = tabmap_get_actual_offset(cur_buf->tabmap, start_offset);
					int y = cur_line + actual_so/VIE_COLS;
					int x = actual_so%VIE_COLS;
					int j;
					if(y<0 || y >= LINES -1) break;
					move(y,VIE_LEFT_MARGIN+x);
					attron(COLOR_PAIR(highlight_color[i]));
					for(j = 0;j<len;j++){
						addch(cur_buf->data[start_offset + j]);
					}
					attroff(COLOR_PAIR(highlight_color[i]));
					offset += match.rm_eo;
				}
				regfree(&preg);
			}
		}
		//shift to next buf
		cur_line += tabmap_get_actual_len(cur_buf->tabmap) / VIE_COLS +1;
		if(cur_line > LINES - 1)break;
		cur_buf = buf_next(cur_buf);
		if(cur_buf == NULL) break;
	}
	return OK;
}
